package org.kabeja.math;

import org.kabeja.dxf.helpers.Point;

/**
 * @author shutao
 * @since 2022/4/24 16:30
 */
public class NURBS {
    protected Point[] controlPoints;
    protected double[] knots;
    protected double[] weights;
    protected int degree;
    protected boolean closed = false;

    public NURBS(Point[] var1, double[] var2, double[] var3, int var4) {
        this.controlPoints = var1;
        this.knots = var2;
        this.weights = var3;
        this.degree = var4;
        if (this.weights.length == 0) {
            this.weights = new double[this.controlPoints.length];
        }

        for(int var5 = 0; var5 < var3.length; ++var5) {
            if (var3[var5] == 0.0D) {
                var3[var5] = 1.0D;
            }
        }

    }

    public double[] getBasicFunctions(int var1, double var2) {
        double[] var4 = new double[this.degree + 1];
        var4[0] = 1.0D;
        double[] var5 = new double[this.degree + 1];
        double[] var6 = new double[this.degree + 1];

        for(int var7 = 1; var7 <= this.degree; ++var7) {
            var5[var7] = var2 - this.knots[var1 + 1 - var7];
            var6[var7] = this.knots[var1 + var7] - var2;
            double var8 = 0.0D;

            for(int var10 = 0; var10 < var7; ++var10) {
                double var11 = var4[var10] / (var6[var10 + 1] + var5[var7 - var10]);
                var4[var10] = var8 + var6[var10 + 1] * var11;
                var8 = var5[var7 - var10] * var11;
            }

            var4[var7] = var8;
        }

        return var4;
    }

    public Point getPointAt(int var1, double var2) {
        Point var4 = new Point();
        double[] var5 = this.getBasicFunctions(var1, var2);
        double var6 = 0.0D;

        for(int var8 = 0; var8 <= this.degree; ++var8) {
            int var9 = var1 - this.degree + var8;
            double var10 = this.weights[var9];
            var4.setX(var4.getX() + var5[var8] * this.controlPoints[var9].getX() * var10);
            var4.setY(var4.getY() + var5[var8] * this.controlPoints[var9].getY() * var10);
            var4.setZ(var4.getZ() + var5[var8] * this.controlPoints[var9].getZ() * var10);
            var6 += var5[var8] * var10;
        }

        var4.setX(var4.getX() / var6);
        var4.setY(var4.getY() / var6);
        var4.setZ(var4.getZ() / var6);
        return var4;
    }

    public Point getPointAt(double var1) {
        int var3 = this.findSpawnIndex(var1);
        return this.getPointAt(var3, var1);
    }

    public int findSpawnIndex(double var1) {
        if (var1 == this.knots[this.controlPoints.length + 1]) {
            return this.controlPoints.length;
        } else {
            int var3 = this.degree;
            int var4 = this.controlPoints.length + 1;

            int var5;
            for(var5 = (var3 + var4) / 2; var1 < this.knots[var5] || var1 >= this.knots[var5 + 1]; var5 = (var3 + var4) / 2) {
                if (var1 < this.knots[var5]) {
                    var4 = var5;
                } else {
                    var3 = var5;
                }
            }

            return var5;
        }
    }

    public Point[] getControlPoints() {
        return this.controlPoints;
    }

    public void setControlPoints(Point[] var1) {
        this.controlPoints = var1;
    }

    public double[] getKnots() {
        return this.knots;
    }

    public void setKnots(double[] var1) {
        this.knots = var1;
    }

    public double[] getWeights() {
        return this.weights;
    }

    public void setWeights(double[] var1) {
        this.weights = var1;
    }

    public int getDegree() {
        return this.degree;
    }

    public void setDegree(int var1) {
        this.degree = var1;
    }

    public boolean isClosed() {
        return this.closed;
    }

    public void setClosed(boolean var1) {
        this.closed = var1;
    }
}
